package observers;
import java.io.Serializable;
import java.util.Vector;
/*
* Copyright 1994-2004 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
@SuppressWarnings("serial")
public class Observable implements Serializable {
private boolean changed = false;
@SuppressWarnings("rawtypes")
private Vector obs;
/** Construct an Observable with zero Observers. */
@SuppressWarnings("rawtypes")
public Observable() {
obs = new Vector();
}
/**
* Adds an observer to the set of observers for this object, provided that
* it is not the same as some observer already in the set. The order in
* which notifications will be delivered to multiple observers is not
* specified. See the class comment.
*
* @param o
* an observer to be added.
* @throws NullPointerException
* if the parameter o is null.
*/
@SuppressWarnings("unchecked")
public synchronized void addObserver(Observer o) {
if (o == null)
throw new NullPointerException();
if (!obs.contains(o)) {
obs.addElement(o);
}
}
/**
* Deletes an observer from the set of observers of this object. Passing
* <CODE>null</CODE> to this method will have no effect.
*
* @param o
* the observer to be deleted.
*/
public synchronized void deleteObserver(Observer o) {
obs.removeElement(o);
}
/**
* If this object has changed, as indicated by the <code>hasChanged</code>
* method, then notify all of its observers and then call the
* <code>clearChanged</code> method to indicate that this object has no
* longer changed.
* <p>
* Each observer has its <code>update</code> method called with two
* arguments: this observable object and <code>null</code>. In other words,
* this method is equivalent to: <blockquote><tt>
* notifyObservers(null)</tt></blockquote>
*
* @see java.util.Observable#clearChanged()
* @see java.util.Observable#hasChanged()
* @see java.util.Observer#update(java.util.Observable, java.lang.Object)
*/
public void notifyObservers() {
notifyObservers(null);
}
/**
* If this object has changed, as indicated by the <code>hasChanged</code>
* method, then notify all of its observers and then call the
* <code>clearChanged</code> method to indicate that this object has no
* longer changed.
* <p>
* Each observer has its <code>update</code> method called with two
* arguments: this observable object and the <code>arg</code> argument.
*
* @param arg
* any object.
* @see java.util.Observable#clearChanged()
* @see java.util.Observable#hasChanged()
* @see java.util.Observer#update(java.util.Observable, java.lang.Object)
*/
public void notifyObservers(Object arg) {
/*
* a temporary array buffer, used as a snapshot of the state of current
* Observers.
*/
Object[] arrLocal;
synchronized (this) {
/*
* We don't want the Observer doing callbacks into arbitrary code
* while holding its own Monitor. The code where we extract each
* Observable from the Vector and store the state of the Observer
* needs synchronization, but notifying observers does not (should
* not). The worst result of any potential race-condition here is
* that: 1) a newly-added Observer will miss a notification in
* progress 2) a recently unregistered Observer will be wrongly
* notified when it doesn't care
*/
if (!changed)
return;
arrLocal = obs.toArray();
clearChanged();
}
for (int i = arrLocal.length - 1; i >= 0; i--)
((Observer) arrLocal[i]).update(this, arg);
}
/**
* Clears the observer list so that this object no longer has any observers.
*/
public synchronized void deleteObservers() {
obs.removeAllElements();
}
/**
* Marks this <tt>Observable</tt> object as having been changed; the
* <tt>hasChanged</tt> method will now return <tt>true</tt>.
*/
protected synchronized void setChanged() {
changed = true;
}
/**
* Indicates that this object has no longer changed, or that it has already
* notified all of its observers of its most recent change, so that the
* <tt>hasChanged</tt> method will now return <tt>false</tt>. This method is
* called automatically by the <code>notifyObservers</code> methods.
*
* @see java.util.Observable#notifyObservers()
* @see java.util.Observable#notifyObservers(java.lang.Object)
*/
protected synchronized void clearChanged() {
changed = false;
}
/**
* Tests if this object has changed.
*
* @return <code>true</code> if and only if the <code>setChanged</code>
* method has been called more recently than the
* <code>clearChanged</code> method on this object;
* <code>false</code> otherwise.
* @see java.util.Observable#clearChanged()
* @see java.util.Observable#setChanged()
*/
public synchronized boolean hasChanged() {
return changed;
}
/**
* Returns the number of observers of this <tt>Observable</tt> object.
*
* @return the number of observers of this object.
*/
public synchronized int countObservers() {
return obs.size();
}
}